// 用来实现自编码的辅助结构
// @Author: zhengqi Wu
// @Description:
// @Version: 1.0.0
// @Date: 2021/3/3 4:02 下午
// @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
//

const encoder = require('./Encoder')
const {Block, createBlockByBuffer} = require('./Block')

//
// 用来实现自编码的辅助结构
//
// @Description:
//

class SelfEncodingBase{
    constructor() {
        this.raw = null
    }

    raw(){
        return this.raw
    }

    /**
     * 对一个实现了 IEncodingAble 接口的对象进行自编码
     * @Description:
     * 1. 用 raw 指针缓存编码的结果；
     * 2. 如果 raw 指针不为空，且指向一个有效的 Block，则直接返回raw
     * 3. 如果 raw 指针为空，或者指向的不是一个有效的 Block，则将对象编码为 Block 之后返回，同时用 raw指针缓存编码的结果
     * @param child
     * @returns {Block} 具体的传递实现了 IEncodingAble 接口的结构体对象的指针
     */
    selfWireEncode(child){
        // To Do: this.raw.isValid()
        // console.log(this.raw)
        // if(!(!this.raw && typeof(this.raw) !== "undefined" && this.raw !==0)){ // 判断is null
        //     return this.raw
        // }
        try{
            let block = easyEncoder(child)
            this.raw = block
            return block
        }catch (e){
            throw e
        }

    }

    /**
     * SelfWireEncodeToBuffer 自编码成字节数组
     * @param child
     * @return {Block}
     */
    selfWireEncodeToBuffer(child){
        // To Do: this.raw.isValid()
        // console.log(this.raw)
        // if(!(!this.raw && typeof(this.raw) !== "undefined" && this.raw !==0)){ // 判断is null
        //     return this.raw
        // }
        try{
            let buffer = easyEncoderToBuf(child)
            this.raw = buffer
            return buffer
        }catch (e){
            throw e
        }

    }
}

/**
 * 自编码辅助函数
 * @param able 实现了wireEncode的对象
 * @return {Block}
 */
function easyEncoder(able){
    try{
        let buffer = easyEncoderToBuf(able)
        // 返回编码的结果
        return createBlockByBuffer(buffer, true)
    }catch (e) {
        throw e
    }

}

function easyEncoderToBuf(able){
    let enc = new encoder.Encoder()
    // 首先测量目标 TLV 的大小
    enc.estimatorReset()
    // DONE 实现 1. 编码初始化 2. 实际执行编码 3. 返回编码的结果
    let targetLen = able.wireEncode(enc)
    try{
        // 编码初始化
        enc = new encoder.Encoder()
        enc.encoderReset(BigInt(targetLen), 0n)
        // 实际执行编码
        able.wireEncode(enc)
        // 返回编码的结果
        let buffer = enc.getBuffer()

        return buffer
    }catch (e){
        throw e
    }
}
module.exports = {
    SelfEncodingBase:SelfEncodingBase,
    easyEncoder:easyEncoder,
    easyEncoderToBuf: easyEncoderToBuf
}